/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package hamming;

//import Gui.Gui;

/**
 *
 * @author Alessandro
 */
public class Codifica_Hamming {

    private String stringaBits;
    private int bitsTotali;
    private int nBitsParita;
    private int bitsDati;
    int avanzamentoProcesso=0;

    public Codifica_Hamming(String bits, int bitsTotati, int bitsDati) {
        this.stringaBits = bits;
        this.bitsTotali = bitsTotati;
        this.bitsDati=bitsDati;
        this.nBitsParita = bitsTotali-bitsDati;
    }

    public String codificaH() {
        int length=stringaBits.length();
        int s[] = new int[bitsTotali];
        int g[][] = new int[nBitsParita][bitsDati];
        int t[] = new int[bitsTotali];
        StringBuilder codifica = new StringBuilder();
        StringBuilder aggiungiBits = new StringBuilder();
        String temp = " ";
        int index = 0;
        int index1 = 0;
        boolean esci = false;
        aggiungiBits.append(stringaBits);
        if (stringaBits.length() % (bitsDati) != 0) {
            int bitAggiunti = (bitsDati) - (stringaBits.length() % (bitsDati));
            for (int f = 0; f < bitAggiunti; f++) {
                aggiungiBits.append("0");
            }
        }//potrei avere inizialmente una stringa che non rispetti i vincoli di lunghezza

        stringaBits = aggiungiBits.toString();
        g = generaMatrice();
        while (!esci) {
            if (index == stringaBits.length()) {
                esci = true;
                break;
            }
       /*     if(Gui.flagBar==true){
            avanzamentoProcesso+=bitsDati;//per la progressBar della gui
               Gui.jProgressBarCH.setValue(Math.round(avanzamentoProcesso/length)*100);
            }*/
            index1 = index + bitsDati;
            temp = stringaBits.substring(index, index1);
            index += bitsDati;
            s = generaS(temp);
            t = prodottoSG(g, s);
            for (int f = 0; f < t.length; f++) {
                codifica.append(Integer.toString(t[f]));
            }
        }
        return codifica.toString();
    }

    private int[] generaS(String stringaBits) {
        char[] ch = stringaBits.toCharArray();
        int s[] = new int[stringaBits.length()];
        for (int i = 0; i < stringaBits.length(); i++) {
            s[i] = Integer.parseInt(String.valueOf(ch[i]));
        }
        return s;
    }

    private int[][] generaMatrice() {
        int[][] identita = new int[bitsDati][bitsDati];
        int[][] matrix = new int[bitsDati][bitsTotali];
        int[][] parita = new int[bitsDati][nBitsParita];
        int l = 0;
        for (int i = 0; i < bitsDati; i++) {
            for (int j = 0; j < bitsDati; j++) {
                if (j == l) {
                    identita[i][j] = 1;
                } else {
                    identita[i][j] = 0;
                }
            }
            l++;
        }  //matrice identità

        parita = generaP();
        int turno = -1;//se turno è 0 devo incrementare la colonna di parità, in caso contrario quella di identità
        int cParita= 0;
        int cIdentita= 0;
        int indice = 0;
        int potenza = (int) Math.pow(2, indice);
        for (int j = 0; j < matrix[0].length; j++) {
            for (int i = 0; i < matrix.length; i++) {
                if (j + 1 == potenza) {
                    matrix[i][j] = parita[i][cParita];
                    turno = 0;
                } else {
                    matrix[i][j] = identita[i][cIdentita];
                    turno = 1;
                }
            }
            if (turno == 0) {
                cParita++;
                indice++;
                potenza = (int) Math.pow(2, indice);
            } else {
                cIdentita++;
            }
        }//creo G
        return matrix;
    }

    private int[] prodottoSG(int[][] g, int[] s) {
        int ris[] = new int[g[0].length];
        for (int r = 0; r < g[0].length; r++) {
            for (int i = 0; i < s.length; i++) {
                ris[r] += s[i] * g[i][r];
                if (ris[r] > 1) {
                    ris[r] = 0;
                }
            }

        }
        return ris;
    }

    private int[][] generaP() {
        int[][] h = new int[bitsTotali - nBitsParita - 1][bitsTotali];
        int[][] p = new int[bitsTotali - nBitsParita][bitsTotali - nBitsParita - 1];
        int[][] pt = new int[bitsTotali - nBitsParita - 1][bitsTotali - nBitsParita];
        int numeroZeri = 0;
        int numeroUni = 1;
        int nBP = nBitsParita;
        boolean shiftaColonna = false;
       
        for (int i = 0; i < h.length; i++) {
            numeroZeri = (int) ((Math.pow(2, i)) - 1);
            numeroUni = (int) Math.pow(2, i);
            for (int j = 0; j < h[0].length; j++) {
                if (numeroZeri <= 0 && numeroUni <= 0) {
                    numeroZeri = (int) Math.pow(2, i);
                    numeroUni = (int) Math.pow(2, i);
                }
                if (numeroZeri > 0) {
                    h[i][j] = 0;
                    numeroZeri--;
                } else {
                    h[i][j] = 1;
                    numeroUni--;
                }
            }
        }//ho generato la matrice H dalla quale estrarrò P
        int potenza = 0;
        int prossimoValore = (int) Math.pow(2, potenza);
        int k = 0;
        for (int j = 0; j < h[0].length; j++) {
            if ((j + 1) == prossimoValore && nBP > 0) {
                nBP--;
                potenza++;
                prossimoValore = (int) Math.pow(2, potenza);
                shiftaColonna = true;
            }
            for (int i = 0; i < pt.length; i++) {
                if (shiftaColonna == false) {
                    pt[i][k] = h[i][j];
                    if (i == pt.length - 1) {
                        k++;
                    }
                }
            }
            shiftaColonna = false;
        }// genero la P trasposta
        for (int i = 0; i < p.length; i++) {
            for (int j = 0; j < p[0].length; j++) {
                p[i][j] = pt[j][i];
            }
        }//ho trasposto la matrice pt
        return p;
    }
}
